<?php
// +----------------------------------------------------------------------
// | 杭州十禾信息科技有限公司
// +----------------------------------------------------------------------
// | Copyright (c) 2013-2015 http://www.shelpe.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: LeePuman <ysyzlsm@163.com>
// +----------------------------------------------------------------------


class OauthException extends Exception{

}


class taobaoAuth
{

	protected $_appKey = TB_AKEY;

	protected $_appSecret = TB_SKEY;

	protected $_oauthToken = "";

	protected $_oauthTokenSecret = "";

	protected $_accessToken = "";

	protected $_accessTokenSecret = "";
	
	protected $_scope = "item,promotion,usergrade";
	
	protected $_callback = '';

	protected $_requestCodeUrl = REQUEST_CODE_URL;

	protected $_requestTokenUrl = REQUEST_TOKEN_URL;

	protected $_signMethod = "HMAC-SHA1";

	protected $format = "json";

	protected $apiVersion = "1.0";

	protected $_customParams = array();
	
    public function __construct( $customeParams = array() ){
		$this->_customParams = array_merge($this->_customParams , $customeParams);
        $this->_callback = defined('AUTH_CALLBACK_URL') ? AUTH_CALLBACK_URL 
        		: $this->_callback = 'http://' . $_SERVER['HTTP_HOST'] . '/code?model=custom';
	}
	
	public function setParams( $params = array() ){
		$this->_customParams = array_merge($this->_customParams , $params);
	}
	
	public function requestCode(){
		$sysParams = array(
			'client_id' => $this->_appKey,
			'response_type' => 'code',
			'redirect_uri' => $this->_callback
			// 'scope' => $this->_scope
		);
		
		if( count($this->_customParams) > 0){
			$sysParams["state"] = array();
			foreach($this->_customParams as $k=>$v){
				$sysParams["state"][] = $k . ":" . $v;
			}
			$sysParams["state"] = implode("^" , $sysParams["state"]);
		}
		
		//generate the url to request the auth code
		$requestUrl = $this->generateRequestUrlFromParams( $this->_requestCodeUrl , $sysParams);
		
		return $requestUrl;
	}
	
	
	public function requestToken( $code = ''){
		$sysParams = array(
			'client_id' => $this->_appKey,
			'client_secret' => $this->_appSecret,
			'grant_type' => "authorization_code",
			'code' => $code,
			'redirect_uri' => $this->_callback,
		);

		if(count($this->_customParams) > 0){
			$sysParams["state"] = array();
			foreach($this->_customParams as $k=>$v){
				$sysParams["state"][] = $k . ":" . $v;
			}
			$sysParams["state"] = implode("^", $sysParams["state"]);
		}
		try{
			$text = $this->httpRequest($this->_requestTokenUrl, $sysParams);
			$response = json_decode($text, true);
		}catch(Exception $e){
			throw new OauthException($e->getMessage());
		}

		if(array_key_exists("error", $response)){
			return false;
		} else {
			return $response;
		}
	}
    
    public function refreshToken($refresh_token=''){
		$sysParams = array(
			'client_id' => $this->_appKey,
			'client_secret' => $this->_appSecret,
			//'response_type' => 'code',
			'grant_type' => "refresh_token",
			'refresh_token' => $refresh_token,
			//'redirect_uri' => $this->_callback,
			//'scope' => $this->_scope
		);

		try{
            $text = $this->httpRequest($this->_requestTokenUrl , $sysParams);
			$response = json_decode(  $text, true );
		}catch(Exception $e){
			// throw new OauthException( $e->getMessage() );
			throw new Exception($e->getMessage());
			
		}      

		if( array_key_exists( "error" , $response) ){
			return false;
		}else{
			return $response;
		}        
    }
	
	protected function generateRequestUrlFromParams( $url ,  $params = array() ){
		$requestUrl = $url . "?";
		foreach($params as $k=>$v){
			$requestUrl .= $k . "=" . $v . "&";
		}
		$requestUrl = substr($requestUrl, 0, -1);
		return $requestUrl;
	}


	public function setCallback($url){
		$this->_callback = $url;
	}

	
	public function set_oauthToken(){

	}

	public function get_token(){
		return array(
				$this->_oauthToken,
				$this->_oauthTokenSecret,
				$this->_accessToken,
				$this->_accessTokenSecret 
		);
	}

	protected function generate_sign($url, $method, $params)
	{
		uksort($params, 'strcmp');
		$pairs = array();
        foreach($params as $key => $value)
        {
			$key = $this->urlencodeRFC3986($key);
            if(is_array($value))
            {
                // If two or more parameters share the same name, they are sorted by their value
                // Ref: Spec: 9.1.1 (1)
                natsort($value);
                foreach($value as $duplicate_value)
                {
                    $pairs[] = $key . '=' . $this->urlencodeRFC3986($duplicate_value);
                }
            }
            else
            {
                $pairs[] = $key . '=' . $this->urlencodeRFC3986($value);
            }
        }
		
        $sign_parts = implode('&', $pairs);
		
		$base_string = implode('&', array( $this->urlencodeRFC3986(strtoupper($method)) , $this->urlencodeRFC3986($url) , $this->urlencodeRFC3986($sign_parts) ));
		//echo $base_string;exit;

        $key_parts = array($this->urlencodeRFC3986($this->_appSecret), $this->urlencodeRFC3986($this->_oauthTokenSecret));
		//var_dump($key_parts);
        $key = implode('&', $key_parts);

		$sign = base64_encode(hash_hmac('sha1', $base_string, $key, true));
		
		return $sign;
    }

	public function httpRequest($url, $postFields = null)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_FAILONERROR, false);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		if ($this->readTimeout) {
			curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
		}
		if ($this->connectTimeout) {
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
		}
		curl_setopt ( $ch, CURLOPT_USERAGENT, "top-sdk-php" );
		//https 请求
		if(strlen($url) > 5 && strtolower(substr($url,0,5)) == "https" ) {
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		}

		if (is_array($postFields) && 0 < count($postFields))
		{
			$postBodyString = "";
			$postMultipart = false;
			foreach ($postFields as $k => $v)
			{
				if("@" != substr($v, 0, 1))//判断是不是文件上传
				{
					$postBodyString .= "$k=" . urlencode($v) . "&"; 
				}
				else//文件上传用multipart/form-data，否则用www-form-urlencoded
				{
					$postMultipart = true;
				}
			}
			unset($k, $v);
			curl_setopt($ch, CURLOPT_POST, true);
			if ($postMultipart)
			{
				curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
			}
			else
			{
				$header = array("content-type: application/x-www-form-urlencoded; charset=UTF-8");
				curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
				curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString,0,-1));
			}
		}
		$reponse = curl_exec($ch);

		if (curl_errno($ch))
		{
			throw new Exception(curl_error($ch),0);
		}
		else
		{
			$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
			if (200 !== $httpStatusCode)
			{
				throw new Exception($reponse,$httpStatusCode);
			}
		}
		curl_close($ch);
		return $reponse;
	}

	protected function urlencodeRFC3986($string){
		return str_replace('%7E','~',rawurlencode($string));
	}

	protected function urldecodeRFC3986($string){
		return rawurldecode($string);
	}


	protected function random_string(){
		return md5(mt_rand(0,10000) * mt_rand(0,10000));
	}


	public function get_access_token($oauth_verifier=""){
		$params["oauth_consumer_key"] = $this->_appKey;
		$params["oauth_token"] = $this->urldecodeRFC3986($this->_oauthToken);
		$params["oauth_signature_method"] = $this->_signMethod;
		$params["oauth_timestamp"] = time();
		$params["oauth_nonce"] = $this->random_string();
		$params["oauth_verifier"] = $oauth_verifier;
		$params["oauth_version"] = "1.0";
		//$params["scope"] = $this->_scope;
		$params["oauth_signature"] = $this->generate_sign( $this->_accessTokenUrl , "GET" , $params );

		$response = $this->http_request($this->_accessTokenUrl, $params,'GET');
        if(!strstr($response , 'oauth_token_secret')){
            return False;
        }
		$access_token = array();
		foreach( explode("&" , $response) as $value){
			list($k , $v) = explode("=" , $value);
			$access_token[$k] = $v;
		}
		return $access_token;		
	}

	public function get($url, $params = array())
	{

        //�����
        $sysParams["oauth_consumer_key"] = $this->_appKey;
        $sysParams["oauth_token"] = urldecode($this->_oauthToken);
        $sysParams["oauth_signature_method"] = $this->_signMethod;
        $sysParams["oauth_timestamp"] = time();
        $sysParams["oauth_nonce"] = $this->random_string();
		$sysParams["oauth_version"] = $this->apiVersion;


       //api ���� 
        $requestParams = array_merge($sysParams , $params);
		$requestParams["oauth_signature"] = $this->generate_sign( $url , "GET" , $requestParams );

		$response = $this->http_request($url, $requestParams , "GET");
        return $response;
	}

	public function setAppkey($appkey, $appSecret, $auth_callback_url)
	{
		$this->_appKey = $appkey;
		$this->_appSecret = $appSecret;
		$this->_callback = $auth_callback_url;
	}
}
